# -*- coding:utf-8 -*-
import os,sys
import re
import traceback
import time
from collections import deque
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), os.pardir, os.pardir))
import supeanut_config
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), os.pardir))
from CommonLib.mylog import mylog
from ExrightsTool import ExrightsTool

'''
作者：supeanut
创建时间：2016-xx-xx xx:xx:xx
功能描述：
相关配置：
	supeanut_config.XXX
历史改动：
	2016-xx-xx: xxxxxx
'''
class TecIndexRecog:
	def __init__(self):
		pass
		

	# 带平滑
	# itemIndex: [1,2,3,4,5]开收高低量
	def MA(self, itemList, itemIndex=2, ma_len=20):
		closes = deque([])
		pinghua_count = 0
		temp_sum = 0.0
		ma_list = []
		for item in itemList:
			pinghua_count += 1
			closes.append(item[itemIndex])
			if pinghua_count > ma_len:
				left_close = closes.popleft()
				temp_sum = temp_sum + item[itemIndex] - left_close
				ma_list.append(temp_sum/ma_len)
			else:
				temp_sum = temp_sum + item[itemIndex]
				ma_list.append(temp_sum/pinghua_count)
		return ma_list

	def BIAS(self, itemList, ma_len=6):
		ma_list = self.MA(itemList, 2, ma_len)
		bias_list = []
		for i in range(len(ma_list)):
			ma = ma_list[i]
			close = itemList[i][2]
			if ma == 0.0:
				bias = (close - 0.001) / 0.001 * 100
			else:
				bias = (close - ma) / ma * 100
			bias_list.append(bias)
			print itemList[i][0]
			print bias
		return bias_list

	# SMA2 = (periodN - cur_wights)/periodN * SMA1 + cur_wights/periodN * value2
	# 平滑：第一天数据即为value0
	def SMA(self, valueList, periodN=3, cur_wights=1):
		if len(valueList) == 1:
			return valueList
		if len(valueList) == 0:
			return []
		pre_value = valueList[0]
		resultList = [valueList[0]]
		for value in valueList[1:]:
			result_value = 1.0 * (periodN - cur_wights)/periodN * pre_value + 1.0 * cur_wights/periodN * value
			resultList.append(result_value)
			pre_value = result_value
		return resultList
			
	def RSV(self, itemList, periodN=9):
		lows = deque([])
		highs = deque([])
		index = 0
		rsvList = []
		for item in itemList:
			index += 1
			lows.append(item[4])
			highs.append(item[3])
			if index <= periodN:
				low = min(lows)
				high = max(highs)
			else:
				low_left = lows.popleft()
				high_left = highs.popleft()
				if low_left == low:
					low = min(lows)
				if high_left == high:
					high = max(highs)
				if item[4] < low:
					low = item[4]
				if item[3] > high:
					high = item[3]
			close = item[2]
			if high <> low:
				rsv = 100.0 * (close - low) / (high - low)
			elif len(rsvList) > 0:
				rsv = rsvList[-1]
			else:
				rsv = 50.0
			rsvList.append(rsv)
		return rsvList
	
	def KDJ(self, itemList, periodN=9, KsmaN=3, DsmaN=3):
		rsvList = self.RSV(itemList, periodN)
		Klist = self.SMA(rsvList, KsmaN, 1)
		Dlist = self.SMA(Klist, DsmaN, 1)
		return [Klist, Dlist]

	# 平滑EMA
	def EMA(self, valueList, days, ):
		return self.SMA(valueList, days+1, 2)

	# 平滑方式的macd
	def MACD(self, itemList, shortN=12, longN=26, midN=9, ):
		closeValues = []
		for item in itemList:
			closeValues.append(item[2])
		shortEMA = self.EMA(closeValues, shortN)
		longEMA = self.EMA(closeValues, longN)
		DIF_LIST = []
		MACD_LIST = []
		for i in range(len(shortEMA)):
			DIF_LIST.append(shortEMA[i] - longEMA[i])
		DEA_LIST = self.EMA(DIF_LIST, midN)
		for i in range(len(DIF_LIST)):
			macd = (DIF_LIST[i] - DEA_LIST[i]) * 2
			MACD_LIST.append(macd)
		return [DIF_LIST, DEA_LIST, MACD_LIST]

	# 两两比较大小，返回比较结果
	# 输入需要比较的list [1,2,3,4]
	# 返回1（小），2（大），0（等于）
	# 顺序为 12,13,14,23,24,34这种
	def pairCom(self, values):
		result_list = []
		length = len(values)
		for i in range(0, length-1):
			for j in range(i+1, length):
				left_value = values[i]
				right_value = values[j]
				if left_value < right_value:
					result_list.append(1)
				elif left_value > right_value:
					result_list.append(2)
				else:
					result_list.append(0)
		return result_list

	# 顺序比大小，返回比较结果
	# 输入需要比较的list[1,2,3,4]
	# 返回1（小），2（大），0（等于）
	# 顺序为 12,23,34
	def orderCom(self, values):
		result_list = []
		for i in range(len(values)-1):
			left_value = values[i]
			right_value = values[i+1]
			if left_value < right_value:
				result_list.append(1)
			elif left_value > right_value:
				result_list.append(2)
			else:
				result_list.append(0)
		return result_list

	# 输入 names = ['a','b','c']
	# 返回 list = ['a_b','a_c','b_c']
	def pairBianLi(self, names):
		result_list = []
		length = len(names)
		for i in range(0, length-1):
			for j in range(i+1, length):
				pair_name = names[i] + '_' + names[j]
				result_list.append(pair_name)
		return result_list

	def MAShapeName(self, ma_days=[5,10,20]):
		ma_days.sort()
		nameList = []
		# 1. close/ma1/ma2/ma3相互之间的位置
		names = ['close']
		for ma_day in ma_days:
			names.append('ma'+str(ma_day))
		nameList.extend(self.pairBianLi(names))
		# 2. 前周期close/ma1/ma2/ma3相互之间的位置
		names = ['preClose']
		for ma_day in ma_days:
			names.append('PreMa'+str(ma_day))
		nameList.extend(self.pairBianLi(names))
		# 3. 前前周期ma与前一周期比大小，前一周期ma与本周期比大小, 顺序为ma1,ma2,ma3
		names = []
		for ma_day in ma_days:
			str_ma = str(ma_day)
			names.append('prePreMa'+str_ma+'_preMa'+str_ma)
			names.append('preMa'+str_ma+'_ma'+str_ma)
		nameList.extend(names)
		# 4. ma1/ma2/ma3本周期斜率与上周期斜率比大小
		names = []
		for ma_day in ma_days:
			str_ma = str(ma_day)
			names.append('ma'+str_ma+'Slope_preMa'+str_ma)
		nameList.extend(names)
		return nameList

	def MAShape(self, itemList, ma_days=[5,10,20], ):
		ma_days.sort()
		# 先计算ma的值，ma_dict
		ma_dict = {}
		for ma_day in ma_days:
			ma_list = self.MA(itemList, 2, ma_day)
			ma_dict[ma_day] = ma_list
		close_list = [k[2] for k in itemList]
		length = len(itemList)
		# 移动窗口为3
		if length < 3:
			return []
		# 移动窗口数据
		win_ma_dict = {}
		for ma_day in ma_days:
			win_ma_dict[ma_day] = deque(ma_dict[ma_day][:3])
		win_close = deque(close_list[:3])
		# 滑动窗口
		result_list = []
		for i in range(2, length):
			datetime = itemList[i][0]
			one_day_features = [datetime]
			# 1. close/ma1/ma2/ma3相互之间的位置
			temp_values = [win_close[2]]
			for ma_day in ma_days:
				temp_values.append(win_ma_dict[ma_day][2])
			comp_res = self.pairCom(temp_values)
			one_day_features.extend(comp_res)
			# 2. 前周期close/ma1/ma2/ma3相互之间的位置
			temp_values = [win_close[1]]
			for ma_day in ma_days:
				temp_values.append(win_ma_dict[ma_day][1])
			comp_res = self.pairCom(temp_values)
			one_day_features.extend(comp_res)
			# 3. 前前周期ma与前一周期比大小，前一周期ma与本周期比大小, 顺序为ma1,ma2,ma3
			temp_values_list = []
			for ma_day in ma_days:
				temp_values_list.append(win_ma_dict[ma_day])
			for temp_value in temp_values_list:
				comp_res = self.orderCom(temp_value)
				one_day_features.extend(comp_res)
			# 4. ma1/ma2/ma3本周期斜率与上周期斜率比大小
			temp_values_list = []
			for ma_day in ma_days:
				ma_slope = win_ma_dict[ma_day][2] - win_ma_dict[ma_day][1]
				pre_ma_slope = win_ma_dict[ma_day][1] - win_ma_dict[ma_day][0]
				temp_values_list.append([ma_slope, pre_ma_slope])
			for temp_value in temp_values_list:
				comp_res = self.orderCom(temp_value)
				one_day_features.extend(comp_res)
			# end. com
			result_list.append(one_day_features)
			if i < (length-1):
				# 窗口移动
				for ma_day in ma_days:
					win_ma_dict[ma_day].popleft()
					win_ma_dict[ma_day].append(ma_dict[ma_day][i+1])
				win_close.popleft()
				win_close.append(close_list[i+1])
		return result_list
			
	# ！！！ 必须和MACDShape中的逻辑相同！！！
	def MACDShapeName(self, ):
		nameList = ['macd_0', 'dif_0', 'dea_0', 'dea_dif', 'dea_macd', 'dif_macd',
			'preMacd_0', 'preDif_0', 'preDea_0', 'preDea_preDif', 'preDea_preMacd', 'preDif_preMacd',
			'macd_preMacd','dif_preDif','dea_preDea', 'preMacd_prePreMacd', 'preDif_prePreDif','preDea_prePreDea',
			'macdSlope_preMacdSlope','difSlope_preDifSlope','deaSlope_preDeaSlope']
		return nameList

	# macd常见的形态模式
	def MACDShape(self, itemList, shortN=12, longN=26, midN=9, ):
		DIF,DEA,MACD = self.MACD(itemList, shortN, longN, midN)
		length = len(itemList)
		# 移动窗口为3
		if length < 3:
			return []
		result_list = []
		winDIF = deque(DIF[:3])
		winDEA = deque(DEA[:3])
		winMACD = deque(MACD[:3])
		for i in range(2, length):
			datetime = itemList[i][0]
			# 1. macd =或<或>0, 代表0,1,2值
			macd3 = winMACD[2]
			if macd3 > 0.01:
				shape_macd_0 = 2
			elif macd3 < -0.01:
				shape_macd_0 = 1
			else:
				shape_macd_0 = 0
			# 2. dif =或<或>0, 代表0,1,2值
			dif3 = winDIF[2]
			if dif3 > 0.01:
				shape_dif_0 = 2
			elif dif3 < -0.01:
				shape_dif_0 = 1
			else:
				shape_dif_0 = 0
			# 3. dea =或<或>0, 代表0,1,2值
			dea3 = winDEA[2]
			if dea3 > 0.01:
				shape_dea_0 = 2
			elif dea3 < -0.01:
				shape_dea_0 = 1
			else:
				shape_dea_0 = 0
			# 4. dea =或<或>dif，代表0,1,2值
			if dea3 > dif3:
				shape_dea_dif = 2
			elif dea3 < dif3:
				shape_dea_dif = 1
			else:
				shape_dea_dif = 0
			# 5. dea =或<或>macd，代表0,1,2值
			if dea3 > macd3:
				shape_dea_macd = 2
			elif dea3 < macd3:
				shape_dea_macd = 1
			else:
				shape_dea_macd = 0
			# 6. dif =或<或>macd，代表0,1,2值
			if dif3 > macd3:
				shape_dif_macd = 2
			elif dif3 < macd3:
				shape_dif_macd = 1
			else:
				shape_dif_macd = 0
			# 7. pre_macd =或<或>0, 代表0,1,2值
			macd2 = winMACD[1]
			if macd2 > 0.01:
				shape_preMacd_0 = 2
			elif macd2 < -0.01:
				shape_preMacd_0 = 1
			else:
				shape_preMacd_0 = 0
			# 8. pre_dif =或<或>0, 代表0,1,2值
			dif2 = winDIF[1]
			if dif2 > 0.01:
				shape_preDif_0 = 2
			elif dif2 < -0.01:
				shape_preDif_0 = 1
			else:
				shape_preDif_0 = 0
			# 9. pre_dea =或<或>0, 代表0,1,2值
			dea2 = winDEA[1]
			if dea2 > 0.01:
				shape_preDea_0 = 2
			elif dea2 < -0.01:
				shape_preDea_0 = 1
			else:
				shape_preDea_0 = 0
			# 10. pre_dea =或<或>pre_dif，代表0,1,2值
			if dea2 > dif2:
				shape_preDea_preDif = 2
			elif dea2 < dif2:
				shape_preDea_preDif = 1
			else:
				shape_preDea_preDif = 0
			# 11. pre_dea =或<或>pre_macd，代表0,1,2值
			if dea2 > macd2:
				shape_preDea_preMacd = 2
			elif dea2 < macd2:
				shape_preDea_preMacd = 1
			else:
				shape_preDea_preMacd = 0
			# 12. pre_dif =或<或>pre_macd，代表0,1,2值
			if dif2 > macd2:
				shape_preDif_preMacd = 2
			elif dif2 < macd2:
				shape_preDif_preMacd = 1
			else:
				shape_preDif_preMacd = 0
			# 13. macd =或<或>pre_macd，代表0,1,2值
			if macd3 > macd2:
				shape_macd_preMacd = 2
			elif macd3 < macd2:
				shape_macd_preMacd = 1
			else:
				shape_macd_preMacd = 0
			# 14. dif =或<或>pre_dif，代表0,1,2值
			if dif3 > dif2:
				shape_dif_preDif = 2
			elif dif3 < dif2:
				shape_dif_preDif = 1
			else:
				shape_dif_preDif = 0
			# 15. dea =或<或>pre_dea，代表0,1,2值
			if dea3 > dea2:
				shape_dea_preDea = 2
			elif dea3 < dea2:
				shape_dea_preDea = 1
			else:
				shape_dea_preDea = 0
			# 16. pre_macd =或<或>pre_pre_macd，代表0,1,2值
			macd1 = winMACD[0]
			if macd2 > macd1:
				shape_preMacd_prePreMacd = 2
			elif macd2 < macd1:
				shape_preMacd_prePreMacd = 1
			else:
				shape_preMacd_prePreMacd = 0
			# 17. pre_dif =或<或>pre_pre_dif，代表0,1,2值
			dif1 = winDIF[0]
			if dif2 > dif1:
				shape_preDif_prePreDif = 2
			elif dif2 < dif1:
				shape_preDif_prePreDif = 1
			else:
				shape_preDif_prePreDif = 0
			# 18. pre_dea =或<或>pre_pre_dea，代表0,1,2值
			dea1 = winDEA[0]
			if dea2 > dea1:
				shape_preDea_prePreDea = 2
			elif dea2 < dea1:
				shape_preDea_prePreDea = 1
			else:
				shape_preDea_prePreDea = 0
			# 19. macd_slope =<> pre_macd_slope, 代表0,1,2值
			macd_slope = macd3 - macd2
			pre_macd_slope = macd2 - macd1
			if macd_slope > pre_macd_slope:
				shape_macdSlope_preMacdSlope = 2
			elif macd_slope < pre_macd_slope:
				shape_macdSlope_preMacdSlope = 1
			else:
				shape_macdSlope_preMacdSlope = 0
			# 20. dif_slope =<> pre_dif_slope, 代表0,1,2值
			dif_slope = dif3 - dif2
			pre_dif_slope = dif2 - dif1
			if dif_slope > pre_dif_slope:
				shape_difSlope_preDifSlope = 2
			elif dif_slope < pre_dif_slope:
				shape_difSlope_preDifSlope = 1
			else:
				shape_difSlope_preDifSlope = 0
			# 21. dea_slope =<> pre_dea_slope, 代表0,1,2值
			dea_slope = dea3 - dea2
			pre_dea_slope = dea2 - dea1
			if dea_slope > pre_dea_slope:
				shape_deaSlope_preDeaSlope = 2
			elif dea_slope < pre_dea_slope:
				shape_deaSlope_preDeaSlope = 1
			else:
				shape_deaSlope_preDeaSlope = 0
			# end. combine
			result_list.append(
				[datetime, shape_macd_0, shape_dif_0, shape_dea_0, shape_dea_dif,
				shape_dea_macd, shape_dif_macd, shape_preMacd_0, shape_preDif_0, shape_preDea_0, 
				shape_preDea_preDif, shape_preDea_preMacd, shape_preDif_preMacd,
				shape_macd_preMacd, shape_dif_preDif, shape_dea_preDea, shape_preMacd_prePreMacd, 
				shape_preDif_prePreDif, shape_preDea_prePreDea, shape_macdSlope_preMacdSlope, 
				shape_difSlope_preDifSlope, shape_deaSlope_preDeaSlope])
			if i < (length-1):
				# 窗口移动
				winDIF.popleft()
				winDIF.append(DIF[i+1])
				winDEA.popleft()
				winDEA.append(DEA[i+1])
				winMACD.popleft()
				winMACD.append(MACD[i+1])
		return result_list


	# eg. 
	# 5日乖离率大于5.0
	# 配合SellStrategy，不可单独使用
	def biasSellSignal(self, itemList, ma_len=5, max_bias=5.0):
		bias_list = self.BIAS(itemList, ma_len)
		datetime_list = []
		for i in range(len(bias_list)):
			datetime = itemList[i][0]
			bias = bias_list[i]
			if bias > max_bias:
				datetime_list.append(datetime)
		return datetime_list

	# 量价配合程度指标,红绿仅为当日K线开收决定
	# 公式：叠加(vol_red - vol_ma ) / vol_ma, 或(vol_ma - vol_green)/vol_ma后的均值
	# 带平滑
	# item_len:计算N个配合度均值，vol_ma_len：每个配合度对应volmaN天ma
	# 返回值：0.0代表配合度一般，大于0.0代表配合度高，值越大越高，小于0.0代表配合度低(背离)，越小越背离
	def priceVolCoordination(self, itemList, item_len, vol_ma_len):
		volCoList = []
		tempVolCo = deque([])
		tempVolCoSumPre = 0.0
		tempVolCoSum = 0.0
		volma_list = self.MA(itemList, 5, vol_ma_len)
		pinghua_count = 0
		if len(itemList) == 0:
			return []
		preItem = itemList[0]
		for i in range(len(itemList)):
			item = itemList[i]
			pinghua_count += 1
			# 计算单个配合度值
			vol = item[5]
			openPrice = item[1]
			closePrice = item[2]
			volma = volma_list[i]
			preClosePrice = preItem[2]
			if openPrice > closePrice:
				volCo = (volma - vol) / volma
			elif openPrice < closePrice:
				volCo = (vol - volma) / volma
			# 开收一致，红绿决定于昨收
			elif preClosePrice > closePrice:
				volCo = (volma - vol) / volma
			elif preClosePrice < closePrice:
				volCo = (vol - volma) / volma
			else:
				volCo = 0.0
			tempVolCo.append(volCo)
			# 非平滑阶段
			if pinghua_count > item_len:
				leftVolCo = tempVolCo.popleft()
				tempVolCoSum = tempVolCoSumPre - leftVolCo + volCo
				volCoList.append(tempVolCoSum/item_len)
			# 平滑阶段
			else:
				tempVolCoSum += volCo
				volCoList.append(sum(tempVolCo)/pinghua_count)
			preItem = item
			tempVolCoSumPre = tempVolCoSum
		return volCoList
	
	# 平滑移动处理的demo函数
	def sample(self, itemList, item_len):
		pinghua_count = 0
		tempItems = deque([])
		result_list = []
		leiJiaSum = 0.0
		if len(itemList) == 0:
			return []
		for i in range(len(itemList)):
			pinghua_count += 1
			item = itemList[i]
			tempItems.append(item)
			# 非平滑阶段
			if pinghua_count > item_len:
				lastLeftItem = tempItems.popleft()
				# 处理tempItems,长度item_len
				pass
				# 或者累加处理模式
				leiJiaSum - lastLeftItem + item
			# 平滑阶段
			else:
				# 处理tempItems,长度pinghua_count
				pass
				# 或者累加处理模式
				leiJiaSum + item
		return result_list
		
	# 红绿比例
	# 红线个数/总K线个数
	def redGreenRatio(self, itemList, item_len):
		pinghua_count = 0
		redTags = deque([])
		ratio_list = []
		if len(itemList) == 0:
			return []
		preItem = itemList[0]
		for i in range(len(itemList)):
			pinghua_count += 1
			item = itemList[i]
			openPrice = item[1]
			closePrice = item[2]
			preClosePrice = preItem[2]
			if openPrice > closePrice:
				redTags.append(0)
			elif openPrice < closePrice:
				redTags.append(1)
			# 开收一致，红绿决定于昨收
			elif preClosePrice > closePrice:
				redTags.append(0)
			elif preClosePrice < closePrice:
				redTags.append(1)
			else:
				redTags.append(0)
			# 非平滑阶段
			if pinghua_count > item_len:
				redTags.popleft()
				ratio_list.append(1.0*sum(redTags)/item_len)
			# 平滑阶段
			else:
				ratio_list.append(1.0*sum(redTags)/pinghua_count)
			preItem = item
		return ratio_list

	# macd形态识别第二版本
	# 输入 [ [dif,dea,macd,[open,close,high,low]], ...]
	# 返回 [shape1, shape2, ...]
	def MACDShapeV2(self, itemWindows, window_size):
		lastItem = itemWindows[-1]
		return [lastItem[0],lastItem[1],lastItem[2]]
		
	# ma形态识别第二版本
	def MAShapeV2(self, itemWindows, window_size):
		lastItem = itemWindows[-1]
		return lastItem[:-1]

if __name__ == '__main__':
	obj = ExrightsTool()
	flag, itemList = obj.getAdjItemList("300248", "pre", "day", None, None)
	obj = TecIndexRecog()
	print obj.MA(itemList, 2, 20)
	print itemList
	#obj.BIAS(itemList, 6)
	#print obj.biasSellSignal(itemList, 6, 5.0)
	#print obj.priceVolCoordination(itemList, 10, 10)
	#print obj.redGreenRatio(itemList, 10)
	#print obj.KDJ(itemList)
	#print obj.MACDShape(itemList)
	print obj.MAShapeName()
	obj.MAShape(itemList)

